//
//  Move.h
//  phi_four
//
//  Created by Snir Gazit on 3/9/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef Move_h
#define Move_h
#include "../HelpLibs/RandomGen.h"
#include "Lattice.h"
#include "../HelpLibs/QmcParameters.h"
namespace ba = boost::accumulators;
typedef ba::accumulator_set<double, ba::stats<ba::tag::mean> > acc;

typedef RandomVariable<MTGen, UniReal> UniRealVariable;
typedef RandomVariable<MTGen, UniInt> UniIntVariable;
typedef RandomVariable<MTGen, Binomial> BinomialVariable;
typedef RandomVariable<MTGen, Discrete> DiscreteVariable;
typedef UniRealVariable::param_type UniRealVariableParams;
typedef UniIntVariable::param_type UniIntVariableParams;
typedef BinomialVariable::param_type BinomialVariableParams;
typedef DiscreteVariable::param_type DiscreteVariableParams;

using namespace std;
class Move {
protected:
	MTGen *eng_;
	Lattice *lat_;
	UniRealVariable zeroOne_;
public:
	void init(MTGen * eng, Lattice *lat);
	void makeMove();
	bool accept(double p);
	bool checkMove();
};

// WormLoop Move
typedef boost::array<double, 2 * 2 * DIM> Weights;

double addRatio(int totalBonds, int otherTotalBonds);
double removeRatio(int totalBonds, int otherTotalBonds);
struct LoopData {
	Site::XYBondData * bondData;
//	double totalWeight;
//	int totalBonds;
};
class CreateLoopMove: public Move {
// typedef typename LoopType::BondData BondData;
	typedef vector<LoopData> LoopDataArray;
	typedef typename LoopDataArray::iterator LoopDataArrayIter;
	UniIntVariable chooseSite_;
	BoltzWeightType CreateRatio_, RemoveRatio_;
	Weights weights_;
	LoopData currentLoopData_;
	LoopDataArray currentLoop_;
	int avWormLength_;
	double g_;
	acc eraseWorm_;
	int loopType_;
public:
	void init(MTGen *eng, Lattice *lat, QmcParameters &qmcParameters,
			BoltzWeightType boltzRatio);
	void setCoupeling(BoltzWeightType boltzRatio, double g);
	int makeMove();
	void nextStep();
	void eraseLoop();
	void getWeights();
	double getEraseProb();
	int chooseDirection();
	bool continueLoop();
	void setAvWormLength(int avWormLength);
	int getLoopType() const;
	void setLoopType(int loopType);
	void switchLoopType();
};

#endif
